/*---- license ----*/
/*-------------------------------------------------------------------------
 Coco.ATG -- Attributed Grammar
 Compiler Generator Coco/R,
 Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
 extended by M. Loeberbauer & A. Woess, Univ. of Linz
 with improvements by Pat Terry, Rhodes University.
 ported to C by Charles Wang <charlesw123456@gmail.com>

 This program is free software; you can redistribute it and/or modify it 
 under the terms of the GNU General Public License as published by the 
 Free Software Foundation; either version 2, or (at your option) any 
 later version.

 This program is distributed in the hope that it will be useful, but 
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
 for more details.

 You should have received a copy of the GNU General Public License along 
 with this program; if not, write to the Free Software Foundation, Inc., 
 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

 As an exception, it is allowed to write an extension of Coco/R that is
 used as a plugin in non-free software.

 If not otherwise stated, any source code generated by Coco/R (other than 
 Coco/R itself) does not fall under the GNU General Public License.
-------------------------------------------------------------------------*/
/*---- enable ----*/
#include  "Parser4Xml.h"
#include  "c/Token.h"

/*---- cIncludes ----*/
/*---- enable ----*/

static void CcxParser_SynErr(CcxParser_t * self, int n);
static const char * set[];

static void
CcxParser_Get(CcxParser_t * self)
{
    if (self->t) CcxScanOper_DecRef(&self->scanner.base, self->t);
    self->t = self->la;
    self->la = CcxScanOper_Scan(&self->scanner.base);
}

static CcsBool_t
CcxParser_StartOf(CcxParser_t * self, int s)
{
    return set[s][self->la->kind] == '*';
}

static void
CcxParser_Expect(CcxParser_t * self, int n)
{
    if (self->la->kind == n) CcxParser_Get(self);
    else CcxParser_SynErr(self, n);
}

#ifdef CcxParser_WEAK_USED
static void
CcxParser_ExpectWeak(CcxParser_t * self, int n, int follow)
{
    if (self->la->kind == n) CcxParser_Get(self);
    else {
	CcxParser_SynErr(self, n);
	while (!CcxParser_StartOf(self, follow)) CcxParser_Get(self);
    }
}

static CcsBool_t
CcxParser_WeakSeparator(CcxParser_t * self, int n, int syFol, int repFol)
{
    if (self->la->kind == n) { CcxParser_Get(self); return TRUE; }
    else if (CcxParser_StartOf(self, repFol)) { return FALSE; }
    CcxParser_SynErr(self, n);
    while (!(CcxParser_StartOf(self, syFol) ||
	     CcxParser_StartOf(self, repFol) ||
	     CcxParser_StartOf(self, 0)))
	CcxParser_Get(self);
    return CcxParser_StartOf(self, syFol);
}
#endif  /* CcxParser_WEAK_USED */

/*---- ProductionsHeader ----*/
/*---- enable ----*/

void
CcxParser_Parse(CcxParser_t * self)
{
    self->t = NULL;
    self->la = CcxScanOper_GetDummy(&self->scanner.base);
    CcxParser_Get(self);
    /*---- ParseRoot ----*/
    /*---- enable ----*/
    CcxParser_Expect(self, 0);
}

CcsBool_t
CcxParser_Finish(CcxParser_t * self)
{
    return self->errpool.errorCount == 0;
}

void
CcxParser_SemErr(CcxParser_t * self, const CcsToken_t * token,
		 const char * format, ...)
{
    va_list ap;
    va_start(ap, format);
    CcsErrorPool_VError(&self->errpool, &token->loc, format, ap);
    va_end(ap);
}

void
CcxParser_SemErrT(CcxParser_t * self, const char * format, ...)
{
    va_list ap;
    va_start(ap, format);
    CcsErrorPool_VError(&self->errpool, &self->t->loc, format, ap);
    va_end(ap);
}

static CcsBool_t
CcxParser_Init(CcxParser_t * self)
{
    self->t = self->la = NULL;
    /*---- constructor ----*/
    /*---- enable ----*/
    return TRUE;
}

CcxParser_t *
CcxParser(CcxParser_t * self, FILE * infp, FILE * errfp)
{
    if (!CcsErrorPool(&self->errpool, errfp)) goto errquit0;
    if (!CcxScanner(&self->scanner, &self->errpool, infp)) goto errquit1;
    if (!CcxParser_Init(self)) goto errquit2;
    return self;
 errquit2:
    CcxScanner_Destruct(&self->scanner);
 errquit1:
    CcsErrorPool_Destruct(&self->errpool);
 errquit0:
    return NULL;
}

CcxParser_t *
CcxParser_ByName(CcxParser_t * self, const char * infn, FILE * errfp)
{
    if (!CcsErrorPool(&self->errpool, errfp)) goto errquit0;
    if (!CcxScanner_ByName(&self->scanner, &self->errpool, infn)) goto errquit1;
    if (!CcxParser_Init(self)) goto errquit2;
    return self;
 errquit2:
    CcxScanner_Destruct(&self->scanner);
 errquit1:
    CcsErrorPool_Destruct(&self->errpool);
 errquit0:
    return NULL;
}

void
CcxParser_Destruct(CcxParser_t * self)
{
    /*---- destructor ----*/
    /*---- enable ----*/
    if (self->t) CcxScanOper_DecRef(&self->scanner.base, self->t);
    if (self->la) CcxScanOper_DecRef(&self->scanner.base, self->la);
    CcxScanner_Destruct(&self->scanner);
    CcsErrorPool_Destruct(&self->errpool);
}

/*---- ProductionsBody ----*/
/*---- enable ----*/

static void
CcxParser_SynErr(CcxParser_t * self, int n)
{
    const char * s; char format[20];
    switch (n) {
    /*---- SynErrors ----*/
    /*---- enable ----*/
    default:
	snprintf(format, sizeof(format), "error %d", n);
	s = format;
	break;
    }
    CcxParser_SemErr(self, self->la, "%s", s);
}

static const char * set[] = {
    /*---- InitSet ----*/
    /*---- enable ----*/
};
